﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace TfsGiggle.Core
{
    /// <summary>
    /// Provides time slot suggestions based on registered eventtimes. 
    /// Plan to use for scheduling best periods for long running tasks, most busy day will determine slots.
    /// </summary>
    public static class ScheduleSuggester
    {
        const int MinutesInADay = 60 * 24;

        /// <summary>
        /// Divide a day into minute slots. Register number of events mapped to a 1 minute slot
        /// </summary>
        static int[] _timeSlotsMinutesPerDay = new int[MinutesInADay];

        /// <summary>
        /// Register time for an event mapped to a 1 minute slot.
        /// </summary>
        /// <param name="eventTime"></param>
        public static void AddEvent(DateTime eventTime)
        {
            Interlocked.Increment(ref _timeSlotsMinutesPerDay[GetMinuteOfDay(eventTime)]);
        }

        /// <summary>
        /// Clear the stats
        /// </summary>
        public static void Clear()
        {
            for (int i = 0; i < _timeSlotsMinutesPerDay.Length; i++)
            {
                if (_timeSlotsMinutesPerDay[i] > 0)
                {
                    _timeSlotsMinutesPerDay[i] = 0;
                }
            }
        }

        /// <summary>
        /// Returns a list of intervals in 1 minutes steps with minute of day and duration to next event
        /// </summary>
        /// <returns></returns>
        public static List<Tuple<TimeSpan, int>> GetTimeslots()
        {
            var intervals = new List<Tuple<TimeSpan, int>>();
            int currentInterval = -1;
            int firstIntervalFound = -1;
            for (int i = 0; i < _timeSlotsMinutesPerDay.Length; i++)
            {
                if (_timeSlotsMinutesPerDay[i] == 0)
                {
                    continue;
                }
                if (currentInterval >= 0)
                {
                    // We got an interval
                    intervals.Add(new Tuple<TimeSpan, int>(TimeSpan.FromMinutes(currentInterval), i - currentInterval));
                }
                else
                {
                    firstIntervalFound = i;
                }
                currentInterval = i;
            }
            if (intervals.Count == 0)
            {
                intervals.Add(new Tuple<TimeSpan, int>(TimeSpan.FromMinutes(0), MinutesInADay));
            }
            else // Add loop-around interval for end of minutes to first occurring event
            {
                intervals.Add(new Tuple<TimeSpan, int>(TimeSpan.FromMinutes(currentInterval), (MinutesInADay - currentInterval) + firstIntervalFound));
            }
            return intervals.OrderByDescending(p => p.Item2).ToList();
        }

        /// <summary>
        /// Return list of registered events containing the mapped day of minute number
        /// </summary>
        /// <returns></returns>
        public static List<int> GetRegisteredEvents()
        { 
            var events = new List<int>();
            for(int i=0;i<_timeSlotsMinutesPerDay.Length;i++)
            {
                if( _timeSlotsMinutesPerDay[i] > 0)
                {
                    events.Add(i);
                }
            }
            return events;
        }

        static private int GetMinuteOfDay(DateTime eventTime)
        {
            return ( eventTime.Hour * 60) + eventTime.Minute;
        }
    }
}